Skip to content

Conversation

@RT2Code
Copy link
Contributor

@RT2Code RT2Code commented Oct 25, 2025

Frames in flight can improve and stabilize the framerate, but they may also introduce some input lag, because frames are buffered ahead of time. Allowing the user to set just one frame in flight, effectively disabling frame queuing, can be useful in scenarios where minimizing input latency is more important than maximizing throughput.

Currently, if the user specify only one frame in flight, the DX12 backend crashes. Just to be clear, this is not a regression introduced by #8961, it was already present beforehand.

The crash occurs because, unlike the example implementation, the backend links the back buffer count directly to the number of frames in flight. If you set 1 frame in flight, the backend will use 1 backbuffer, but DXGI_SWAP_EFFECT_FLIP_DISCARD requires at least 2 back buffers, causing the swapchain creation to fail.

To fix this, it was necessary to decouple the back buffer count from the frame in flight count. The back buffer related members have been moved from ImGui_ImplDX12_FrameContext to a new structure, ImGui_ImplDX12_Backbuffer, allowing each to have a different count. I also added a BackBuffer field to ImGui_ImplDX12_InitInfo so users can configure it explicitly.

…itInfo::BackBuffer and add support for a single frame in flight
@kjm99d
Copy link

kjm99d commented Oct 30, 2025

With this change the waitable object latency is tied to numBackbuffer.
If a user sets NumFramesInFlight = 1 but keeps two back buffers (needed for flip discard), latency goes back to 2 and input lag returns.
Can we keep SetMaximumFrameLatency(bd->numFramesInFlight) so the user can effectively opt into one frame in flight?

@RT2Code
Copy link
Contributor Author

RT2Code commented Nov 10, 2025

Did you check the latency manually? From what I understand, since in D3D12 we explicitly wait for a new frame context to become available before rendering, the number of frames queued for presentation should never exceed the number of frames in flight. Therefore, if the maximum frame latency is set to 2 but there is only 1 frame in flight, you will never queue more than one frame, the maximum frame latency is never reached, and the resulting latency should be identical to having it set to 1.

In the opposite case, if there are more frames in flight than back buffers, there still shouldn’t be any difference, since each frame requires a free back buffer to be presented, meaning we can’t present more frames than there are back buffers.

SetMaximumFrameLatency is more important for D3D11, where it's the only way to control frames in flight count. In D3D12, however, I believe it's mostly redundant.

That said, you’re right: since SetMaximumFrameLatency is conceptually tied to frames in flight, it should be set to the same value for consistency. I’ve fixed it.

@RT2Code
Copy link
Contributor Author

RT2Code commented Nov 10, 2025

Tagging @walbourn since he’s an expert on this topic.

If you have a moment, I’d appreciate it if you could check my previous message to make sure I’m not saying anything incorrect, and share your recommendation for the correct SetMaximumFrameLatency value.

@walbourn
Copy link

walbourn commented Nov 10, 2025

Is it typical usage for IMGUI to render directly to the DXGI swapchain for Direct3D scenarios? In most 'professional' render setups, there are generally render-to-texture steps done before it is presented to the swapchain.

@RT2Code
Copy link
Contributor Author

RT2Code commented Nov 10, 2025

Thanks for your quick reply. That’s the approach used in the default ImGui example files for the main viewport, but users are free to render ImGui in any way they prefer. It can absolutely be rendered to a separate texture, but the examples are only meant to demonstrate how to use ImGui and as such, should be kept as simple as possible.

This PR is primarily concerned with correct DirectX usage rather than ImGui itself. I have reviewed all the available documentation and resources I could find, but I'm still unsure about the role of SetMaximumFrameLatency when frames in flight (aka one command buffer per frame) are managed manually with fences.

@walbourn
Copy link

walbourn commented Nov 11, 2025

My understanding is that SetMaximumFrameLatency is only applicable to 'waitable' swapchains, i.e. those that can use DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT which doesn't apply to 'classic' Win32 windowing. IOW: It only applies to UWP or if you are using DirectComposition.

@walbourn
Copy link

Note this could well have changed since I last looked at it. This Desktop sample uses it: https://github.com/microsoft/DirectX-Graphics-Samples/blob/master/Samples/Desktop/D3D12nBodyGravity/src/D3D12nBodyGravity.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants